package Cmdquenue;
#Class for Dealing with Commands
use warnings;
use strict;
use Carp;
use Cmd;

our $VERSION = 0.01;
$MyPackage::VERSION = 0.01;
use vars qw($VERSION);
my @cmdquenue;
my %approvednick;
my %db_nicklist;

#Command Quenue Vars
#kernel  - Refenece to Kernel object
#dbalias - Database name
#dbh_id  - Database handle id

#Cmd Object Vars
#Command  - Name of Command
#Level    - Required Access level
#Ready    - Is Command ready to excute
#Nick     - Nickname of calling Command

#Nick Ojbect Vars
#Nickname - Nickname
#Level    - Nick Level
#Approved - Is nick approved

#Access Level:
#- Blocked: -1
#- User: 0
#- Voice: 1
#- Admin: 2
#- Owner: 3


#Constuction
sub new
{
    my $class = shift;
    my $cmdquenue = {@_};
    bless $cmdquenue, $class;

    $cmdquenue->_init;
    return $cmdquenue;
}

sub _init
{
    my $cmdquenue = shift;
}

##Quenue/Object Control
sub dbalias
{
    my $cmdquenue = shift;
    unless (ref $cmdquenue)
    {
        croak "dbalias() should be called with an object, not a class"; #Error Handling.
    }
    my $newdbalias = shift;
    if(defined $newdbalias)
    {
        $cmdquenue->{dbalias} = $newdbalias;
    }

    return $cmdquenue->{dbalias};
}

sub kernel
{
    my $cmdquenue = shift;
    unless (ref $cmdquenue)
    {
        croak "kernel() should be called with an object, not a class"; #Error Handling.
    }
    my $newkernel = shift;

    if(defined $newkernel)
    {
        $cmdquenue->{kernel} = $newkernel;
    }

    return $cmdquenue->{kernel};
}

sub addcommand
{
    my $cmdquenue = shift;
    unless (ref $cmdquenue)
    {
        croak "addcommand() should be called with an object, not a class"; #Error Handling.
    }

    my $cmd = shift;

    unless (exists ${$cmd}{command}
        && exists ${$cmd}{level}
        && exists ${$cmd}{nick}
        && exists ${$cmd}{where}
        )
    {
        croak "addcommmand() is missing required arguments";
    }

    #Check to see if Nick is allowed to use command. If not allowed, no responce is given
    #If not identifed, send privmsg to user and gently remind them.
    #Could do 0 - not allowed, 1 - allowed, 2 - not identifed, 3 - not registered

    my $command = ${$cmd}{command};
    my $requiredlvl = ${$cmd}{level};
    my $where = ${$cmd}{where};
    my $lvl;
    my $nick = ${$cmd}{nick};
    my $approvednick = 0; #Is Nick Approved
    my $args;
    if (exists ${$cmd}{args})
    {
        $args = ${$cmd}{args};
    }

    #Check to see if Nick Exists in Cache - If we have one, it means that the nick already authroized for their session
    if (exists $approvednick{$nick})
    {
        $lvl = $approvednick{$nick};
        $approvednick = 1;
    }

    if ($approvednick == 0)
    {
        #Check to see if User exists in the database
        # if does exists
        if (exists $db_nicklist{$nick})
        {
            $lvl = $db_nicklist{$nick};
        } else {
            $lvl = 0
        }
            #Check if required level is 0, set command ready 1 else set -1
    }

    #print "$command : $requiredlvl -> $nick : $lvl - $approvednick\n";

    #-1 is Banned/Ignored users
    if($lvl == -1)
    {
        #Ignore Banned users completely
        return 0;
    }

    if($requiredlvl == 0)
    {
        #Add Command(With Ready set to 1)
        _addcmdobj
        (
            $cmdquenue,
            command  => $command,
            where    => $where,
            ready    => 1,
            nick     => $nick,
            level    => $lvl,
            args     => $args,
         );
        return 1;
    }

    #Level is too low for command
    if ($lvl < $requiredlvl)
    {
        #Add Command(With ready set to -1)
        _addcmdobj
        (
            $cmdquenue,
            command  => $command,
            where    => $where,
            ready    => -1,
            nick     => $nick,
            level    => $lvl,
            args     => $args,
        );
        return 1;
    }

    #If Required level is 1 or above, then find status of nick via NICKSERV. Expect 3 (logged in via password)
    #This is for irc.coldfront.net. Other nickserv might report differently. Such, some might have 3 mean logged in via Secure Hash, etc.

    if ($approvednick == 0)
    {
        #Send NICKSERV request then add command with ready = 0

        $cmdquenue->{kernel}->post('IRC' => 'privmsg', 'NICKSERV', 'STATUS ' . $nick);
        _addcmdobj
        (
            $cmdquenue,
            command  => $command,
            where    => $where,
            ready    => 0,
            nick     => $nick,
            level    => $lvl,
            args     => $args,
        );
    } else {
        #level is ok, add command ready 1
        _addcmdobj
        (
            $cmdquenue,
            command  => $command,
            where    => $where,
            ready    => 1,
            nick     => $nick,
            level    => $lvl,
            args     => $args,
        );
    }

     return 1;
}


##### Commmands Control ####

sub endofquenue
{
    my $bool;
    if(defined $cmdquenue[0])
    {
        $bool = 0;
    } else {
        $bool = 1;
    }

    return $bool;
}

sub cmddone
{
    shift @cmdquenue;
    return;
}

#Exposes data from current object. (The Command Object that's next in quenue. $cmdquenue[0])
sub command
{
    return $cmdquenue[0]->{command};
}

sub ready
{
    return $cmdquenue[0]->{ready};
}

sub nick
{
    return $cmdquenue[0]->{nick};
}

sub level
{
    return $cmdquenue[0]->{level};
}

sub args
{
    return $cmdquenue[0]->{args};
}

sub where
{
    return $cmdquenue[0]->{where};
}

sub addapprovednick
{
    my $cmdquenue = shift;
    my $nick = shift;
    if (exists $db_nicklist{$nick})
    {
        $approvednick{$nick} = $db_nicklist{$nick};
    }
    
    foreach my $cmdojb (@cmdquenue)
    {
        if ($cmdojb->{nick} = $nick)
        {
            if ($cmdojb->{ready} == 0)
            {
                $cmdojb->ready(1);
                $cmdquenue->{kernel}->yield('nick_approved', $cmdquenue);

            }
        }
    }

    return;
}

#Remove a single approved nick
sub removedapprovednick
{
    my $cmdquneue = shift;
    my $nick = shift;
    if (exists $approvednick{$nick})
    {
        delete $approvednick{$nick};
    }
}

#Remove all approved nicks.
sub resetapprovednick
{
    undef %approvednick;
}

sub unapprovednick
{
    my $cmdquenue = shift;
    my $nick = shift;
#     if (exists $db_nicklist{$nick})
#     {
#         $approvednick{$nick} = $db_nicklist{$nick};
#     }

    foreach my $cmdojb (@cmdquenue)
    {
        if ($cmdojb->{nick} = $nick)
        {
            if ($cmdojb->{ready} == 0)
            {
                $cmdojb->ready(-1);
                $cmdquenue->{kernel}->yield('nick_unapproved', $cmdquenue);
            }
        }
    }

    return;
}

#DB Refresh - Update/set/remove nick
sub dbrefresh
{
    my $cmdquenue = shift;
    my $nicklist = shift;
    %db_nicklist = %{$nicklist};
    return;
}

#Private Methods
sub _addcmdobj
{
    my $cmdquenue = shift;
    my %arg = @_;
    #print %arg;
    #print "\n"; - debug

    my $cmdobj = Cmd->new
        (
            command  => $arg{command},
            where    => $arg{where},
            ready    => $arg{ready},
            nick     => $arg{nick},
            level    => $arg{level},
            args     => $arg{args},
         );

    push @cmdquenue, $cmdobj;

    $cmdquenue->{kernel}->yield('command_added', $cmdquenue);

    return;
}
1;